// 版权归Go作者所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build faketime&！windows 

// Faketime当前在windows上不受支持。这需要修改syscall。编写以调用syscall。faketimeWrite，
// 将Stdout和Stderr句柄转换为FDs 1和2。
// （见第192739章第3页）

package runtime

import "unsafe"

// faketime是自1970年以来
// 游乐场的模拟时间，单位为纳秒。
var faketime int64 = 1257894000000000000

var faketimeState struct {
	lock mutex

	// LastFaketTime是写入fd 1或2的最后一个FaketTime值。
	lastfaketime int64

	// lastfd是写入lastfaketime的fd。
	// 
	// 对同一fd的后续写入可能使用相同的
	// 时间戳，但如果fd 
	// 发生变化，时间戳必须增加。
	lastfd uintptr
}

// go:nosplit 
func nanotime() int64 {
	return faketime
}

// go:linkname time_now time。现在
func time_now() (sec int64, nsec int32, mono int64) {
	return faketime / 1e9, int32(faketime % 1e9), faketime
}

// write类似于Unix write系统调用。
// 我们必须避免写入障碍，以避免潜在的死锁
// 写入调用。
// go:nowritebarrierrec 
func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
	if !(fd == 1 || fd == 2) {
		// 做一个普通的书写。
		return write1(fd, p, n)
	}

	// 使用播放头写入。

	// 首先，锁定以避免交叉写入。
	lock(&faketimeState.lock)

	// 如果当前fd与上一次写入的fd不匹配，
	// 请确保时间戳严格大于此值。这样，即使我们单独阅读fds，我们也可以恢复原始订单。
	t := faketimeState.lastfaketime
	if fd != faketimeState.lastfd {
		t++
		faketimeState.lastfd = fd
	}
	if faketime > t {
		t = faketime
	}
	faketimeState.lastfaketime = t

	// 播放头：0p B<8字节时间><4字节数据长度>（大端）
	var buf [4 + 8 + 4]byte
	buf[2] = 'P'
	buf[3] = 'B'
	tu := uint64(t)
	buf[4] = byte(tu >> (7 * 8))
	buf[5] = byte(tu >> (6 * 8))
	buf[6] = byte(tu >> (5 * 8))
	buf[7] = byte(tu >> (4 * 8))
	buf[8] = byte(tu >> (3 * 8))
	buf[9] = byte(tu >> (2 * 8))
	buf[10] = byte(tu >> (1 * 8))
	buf[11] = byte(tu >> (0 * 8))
	nu := uint32(n)
	buf[12] = byte(nu >> (3 * 8))
	buf[13] = byte(nu >> (2 * 8))
	buf[14] = byte(nu >> (1 * 8))
	buf[15] = byte(nu >> (0 * 8))
	write1(fd, unsafe.Pointer(&buf[0]), int32(len(buf)))

	// 写入实际数据。
	res := write1(fd, p, n)

	unlock(&faketimeState.lock)
	return res
}
